{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Introduction to atomman: POSCAR conversions\n",
    "\n",
    "__Lucas M. Hale__, [lucas.hale@nist.gov](mailto:lucas.hale@nist.gov?Subject=ipr-demo), _Materials Science and Engineering Division, NIST_.\n",
    "    \n",
    "[Disclaimers](http://www.nist.gov/public_affairs/disclaimer.cfm) "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1. Introduction<a id='section1'></a>\n",
    "\n",
    "The POSCAR format is the default atomic configuration representation used by the VASP DFT software.  As such, a large amount of reference data can be found in the POSCAR format and the format is supported by many different atomistic programs.\n",
    "\n",
    "Currently, atomman offers basic support for loading/dumping the box and atomic coordination information stored in the POSCAR format.  The reading and writing of additional flags and values is not yet included."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Library Imports**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "atomman version = 1.4.0\n",
      "Notebook executed on 2021-08-04\n"
     ]
    }
   ],
   "source": [
    "# Standard Python libraries\n",
    "import datetime\n",
    "\n",
    "# http://www.numpy.org/\n",
    "import numpy as np\n",
    "\n",
    "import atomman as am\n",
    "import atomman.unitconvert as uc\n",
    "\n",
    "# Show atomman version\n",
    "print('atomman version =', am.__version__)\n",
    "\n",
    "# Show date of Notebook execution\n",
    "print('Notebook executed on', datetime.date.today())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Generate test system information (CsCl)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "avect =  [ 3.200,  0.000,  0.000]\n",
      "bvect =  [ 0.000,  3.200,  0.000]\n",
      "cvect =  [ 0.000,  0.000,  3.200]\n",
      "origin = [ 0.000,  0.000,  0.000]\n",
      "natoms = 2\n",
      "natypes = 2\n",
      "symbols = ('Cs', 'Cl')\n",
      "pbc = [ True  True  True]\n",
      "per-atom properties = ['atype', 'pos', 'charge', 'stress']\n",
      "     id |   atype |  pos[0] |  pos[1] |  pos[2]\n",
      "      0 |       1 |   0.000 |   0.000 |   0.000\n",
      "      1 |       2 |   1.600 |   1.600 |   1.600\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>atype</th>\n",
       "      <th>pos[0]</th>\n",
       "      <th>pos[1]</th>\n",
       "      <th>pos[2]</th>\n",
       "      <th>charge</th>\n",
       "      <th>stress[0][0]</th>\n",
       "      <th>stress[0][1]</th>\n",
       "      <th>stress[0][2]</th>\n",
       "      <th>stress[1][0]</th>\n",
       "      <th>stress[1][1]</th>\n",
       "      <th>stress[1][2]</th>\n",
       "      <th>stress[2][0]</th>\n",
       "      <th>stress[2][1]</th>\n",
       "      <th>stress[2][2]</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>1.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1</td>\n",
       "      <td>2</td>\n",
       "      <td>1.6</td>\n",
       "      <td>1.6</td>\n",
       "      <td>1.6</td>\n",
       "      <td>-1.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   atype  pos[0]  pos[1]  pos[2]  charge  stress[0][0]  stress[0][1]  \\\n",
       "0      1     0.0     0.0     0.0     1.0           0.0           0.0   \n",
       "1      2     1.6     1.6     1.6    -1.0           0.0           0.0   \n",
       "\n",
       "   stress[0][2]  stress[1][0]  stress[1][1]  stress[1][2]  stress[2][0]  \\\n",
       "0           0.0           0.0           0.0           0.0           0.0   \n",
       "1           0.0           0.0           0.0           0.0           0.0   \n",
       "\n",
       "   stress[2][1]  stress[2][2]  \n",
       "0           0.0           0.0  \n",
       "1           0.0           0.0  "
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Generate box\n",
    "alat = uc.set_in_units(3.2, 'angstrom')\n",
    "box = am.Box(a=alat, b=alat, c=alat)\n",
    "\n",
    "# Generate atoms with atype, pos, charge, and stress properties\n",
    "atype = [1, 2]\n",
    "pos = [[0,0,0], [0.5, 0.5, 0.5]]\n",
    "charge = uc.set_in_units([1, -1], 'e')\n",
    "stress = uc.set_in_units(np.zeros((2, 3, 3)), 'MPa')\n",
    "atoms = am.Atoms(pos=pos, atype=atype, charge=charge, stress=stress)\n",
    "\n",
    "# Build system from box and atoms, and scale atoms\n",
    "system = am.System(atoms=atoms, box=box, scale=True, symbols=['Cs', 'Cl'])\n",
    "\n",
    "# Print system information\n",
    "print(system)\n",
    "system.atoms_df()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2. System.dump('poscar')<a id='section2'></a>\n",
    "\n",
    "Generates a POSCAR file based on the System.  __Note__: the POSCAR format only captures per-atom data for each atom's type and position.  Therefore, it does not offer a lossless representation of a System object.\n",
    "\n",
    "Parameters\n",
    "\n",
    "- **f** (*str or file-like object, optional*) File path or file-like object to write the content to.  If not given, then the content is returned as a str.\n",
    "\n",
    "- **header** (*str, optional*) The comment line to place at the top of the file. Default value is ''.\n",
    "\n",
    "- **symbols** (*list of str, optional*) List of the element symbols that correspond to the atom types.  If not given, will use system.symbols if set, otherwise no element content will be included.\n",
    "\n",
    "- **coordstyle** (*str, optional*) The poscar coordinate style to use: 'cartesian' or 'direct' (i.e. box relative).  Default value is 'direct'.  \n",
    "\n",
    "- **box_scale** (*float, optional*) A universal scaling constant applied to the box vectors. Default value is 1.0.\n",
    "\n",
    "- **float_format** (*str, optional*) c-style format for printing the floating point numbers. Default value is '%.13e'.\n",
    "        \n",
    "Returns\n",
    "\n",
    "- **poscar_str** (*str*) String of the poscar object (only returned if fname is not given)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Dump with mostly default values"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Test POSCAR content for CsCl\n",
      "1.0000000000000e+00\n",
      "3.2000000000000e+00 0.0000000000000e+00 0.0000000000000e+00\n",
      "0.0000000000000e+00 3.2000000000000e+00 0.0000000000000e+00\n",
      "0.0000000000000e+00 0.0000000000000e+00 3.2000000000000e+00\n",
      "Cs Cl\n",
      "1 1 \n",
      "direct\n",
      "0.0000000000000e+00 0.0000000000000e+00 0.0000000000000e+00\n",
      "5.0000000000000e-01 5.0000000000000e-01 5.0000000000000e-01\n"
     ]
    }
   ],
   "source": [
    "poscar = system.dump('poscar', header='Test POSCAR content for CsCl')\n",
    "print(poscar)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Change parameters and repeat"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Test POSCAR content for CsCl\n",
      "3.200000\n",
      "1.000000 0.000000 0.000000\n",
      "0.000000 1.000000 0.000000\n",
      "0.000000 0.000000 1.000000\n",
      "Cs Cl\n",
      "1 1 \n",
      "Cartesian\n",
      "0.000000 0.000000 0.000000\n",
      "1.600000 1.600000 1.600000\n"
     ]
    }
   ],
   "source": [
    "poscar = system.dump('poscar', header='Test POSCAR content for CsCl',\n",
    "                    coordstyle='Cartesian', box_scale=3.2, float_format='%f')\n",
    "print(poscar)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3. atomman.load('poscar')<a id='section3'></a>\n",
    "\n",
    "POSCAR files can be read in to an atomman.System using atomman.load() with the POSCAR style.\n",
    "\n",
    "Parameters\n",
    "\n",
    "- **poscar** (*str or file-like object*) The POSCAR content to read.\n",
    "\n",
    "- **symbols** (*tuple, optional*) Allows the list of element symbols to be assigned during loading.  Useful if the symbols for the model differ from the standard element tags or if the poscar file has no elemental information.\n",
    "\n",
    "- **prop** (*dict, optional*) Dictionary containing any extra per-atom properties to include.\n",
    "    \n",
    "Returns\n",
    "\n",
    "- **system** (*atomman.System*) The system object associated with the data model."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Load the poscar generated above.  Note that charge and stress are missing because POSCAR cannot represent them."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "avect =  [ 3.200,  0.000,  0.000]\n",
      "bvect =  [ 0.000,  3.200,  0.000]\n",
      "cvect =  [ 0.000,  0.000,  3.200]\n",
      "origin = [ 0.000,  0.000,  0.000]\n",
      "natoms = 2\n",
      "natypes = 2\n",
      "symbols = ('Cs', 'Cl')\n",
      "pbc = [ True  True  True]\n",
      "per-atom properties = ['atype', 'pos']\n",
      "     id |   atype |  pos[0] |  pos[1] |  pos[2]\n",
      "      0 |       1 |   0.000 |   0.000 |   0.000\n",
      "      1 |       2 |   1.600 |   1.600 |   1.600\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>atype</th>\n",
       "      <th>pos[0]</th>\n",
       "      <th>pos[1]</th>\n",
       "      <th>pos[2]</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1</td>\n",
       "      <td>2</td>\n",
       "      <td>1.6</td>\n",
       "      <td>1.6</td>\n",
       "      <td>1.6</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   atype  pos[0]  pos[1]  pos[2]\n",
       "0      1     0.0     0.0     0.0\n",
       "1      2     1.6     1.6     1.6"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Load poscar and pass in prop dictionary\n",
    "poscar_system = am.load('poscar', poscar)\n",
    "print(poscar_system)\n",
    "poscar_system.atoms_df()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If additional properties were stored elsewhere, they can be passed in during loading using the prop parameter"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "avect =  [ 3.200,  0.000,  0.000]\n",
      "bvect =  [ 0.000,  3.200,  0.000]\n",
      "cvect =  [ 0.000,  0.000,  3.200]\n",
      "origin = [ 0.000,  0.000,  0.000]\n",
      "natoms = 2\n",
      "natypes = 2\n",
      "symbols = ('Cs', 'Cl')\n",
      "pbc = [ True  True  True]\n",
      "per-atom properties = ['atype', 'pos', 'charge', 'stress']\n",
      "     id |   atype |  pos[0] |  pos[1] |  pos[2]\n",
      "      0 |       1 |   0.000 |   0.000 |   0.000\n",
      "      1 |       2 |   1.600 |   1.600 |   1.600\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>atype</th>\n",
       "      <th>pos[0]</th>\n",
       "      <th>pos[1]</th>\n",
       "      <th>pos[2]</th>\n",
       "      <th>charge</th>\n",
       "      <th>stress[0][0]</th>\n",
       "      <th>stress[0][1]</th>\n",
       "      <th>stress[0][2]</th>\n",
       "      <th>stress[1][0]</th>\n",
       "      <th>stress[1][1]</th>\n",
       "      <th>stress[1][2]</th>\n",
       "      <th>stress[2][0]</th>\n",
       "      <th>stress[2][1]</th>\n",
       "      <th>stress[2][2]</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>1.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1</td>\n",
       "      <td>2</td>\n",
       "      <td>1.6</td>\n",
       "      <td>1.6</td>\n",
       "      <td>1.6</td>\n",
       "      <td>-1.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   atype  pos[0]  pos[1]  pos[2]  charge  stress[0][0]  stress[0][1]  \\\n",
       "0      1     0.0     0.0     0.0     1.0           0.0           0.0   \n",
       "1      2     1.6     1.6     1.6    -1.0           0.0           0.0   \n",
       "\n",
       "   stress[0][2]  stress[1][0]  stress[1][1]  stress[1][2]  stress[2][0]  \\\n",
       "0           0.0           0.0           0.0           0.0           0.0   \n",
       "1           0.0           0.0           0.0           0.0           0.0   \n",
       "\n",
       "   stress[2][1]  stress[2][2]  \n",
       "0           0.0           0.0  \n",
       "1           0.0           0.0  "
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Define prop with charge and stress from the original system\n",
    "prop = {}\n",
    "prop['charge'] = system.atoms.charge\n",
    "prop['stress'] = system.atoms.stress\n",
    "\n",
    "# Load poscar and pass in prop dictionary\n",
    "poscar_system = am.load('poscar', poscar, prop=prop)\n",
    "print(poscar_system)\n",
    "poscar_system.atoms_df()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "__Note__: POSCAR files occasionally have additional flags and lines.  Right now, these are ignored by atomman."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "avect =  [ 3.200,  0.000,  0.000]\n",
      "bvect =  [ 0.000,  3.200,  0.000]\n",
      "cvect =  [ 0.000,  0.000,  3.200]\n",
      "origin = [ 0.000,  0.000,  0.000]\n",
      "natoms = 2\n",
      "natypes = 2\n",
      "symbols = ('Cs', 'Cl')\n",
      "pbc = [ True  True  True]\n",
      "per-atom properties = ['atype', 'pos']\n",
      "     id |   atype |  pos[0] |  pos[1] |  pos[2]\n",
      "      0 |       1 |   0.000 |   0.000 |   0.000\n",
      "      1 |       2 |   1.600 |   1.600 |   1.600\n"
     ]
    }
   ],
   "source": [
    "poscar=\"\"\"Test POSCAR with extra flags and lines\n",
    "3.200000\n",
    "1.000000 0.000000 0.000000\n",
    "0.000000 1.000000 0.000000\n",
    "0.000000 0.000000 1.000000\n",
    "Cs Cl\n",
    "1 1 \n",
    "Cartesian\n",
    "0.000000 0.000000 0.000000 1 0 0\n",
    "1.600000 1.600000 1.600000 1 0 0\n",
    "\n",
    "extra data down here\n",
    "\n",
    "\"\"\"\n",
    "poscar_system = am.load('poscar', poscar)\n",
    "print(poscar_system)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    " "
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
